#include <stdio.h>
#include <stdlib.h> // for malloc, free, exit, NULL
#include <unistd.h> // for getpid, getchar
#include <string.h> // for memset (optional, but good practice)
#include <sys/types.h> // for pid_t

// 定义常量，方便修改
#define MALLOC_SIZE_128M (128 * 1024 * 1024) // 128MB
#define MALLOC_SIZE_1024M (1024 * 1024 * 1024) // 1024MB (1GB)
#define MALLOC_SIZE_64M (64 * 1024 * 1024)  // 64MB
#define NUM_ALLOCS 6

// 辅助函数：打印状态信息并暂停程序
void check_memory_status(const char* message) {
    pid_t pid = getpid();
    printf("\n--- %s ---\n", message);
    printf("当前进程 PID: %d\n", pid);
    printf("请在另一个终端执行以下命令查看内存状态:\n");
    printf("  cat /proc/%d/maps\n", pid);
    printf("  cat /proc/%d/status | grep Vm\n", pid); // 只看 Vm 开头的行
    printf("\n按 Enter 键继续...\n");
    getchar(); // 等待用户按 Enter
}

int main() {
    void *ptrs[NUM_ALLOCS]; // 用于存储 6 个 128MB 块的指针
    void *large_ptr = NULL;  // 用于存储 1024MB 块的指针
    void *final_ptr = NULL;  // 用于存储 64MB 块的指针
    int i;

    // 初始化指针数组为 NULL
    memset(ptrs, 0, sizeof(ptrs));

    printf("程序开始，进程 ID: %d\n", getpid());

    // 0. 初始状态
    check_memory_status("初始状态 (分配任何大内存之前)");

    // 1. 连续分配 6 个 128MB 内存块
    printf("\n[操作 1] 正在分配 6 * 128MB 内存块...\n");
    for (i = 0; i < NUM_ALLOCS; i++) {
        ptrs[i] = malloc(MALLOC_SIZE_128M);
        if (ptrs[i] == NULL) {
            perror("分配 128MB 内存失败");
            // 清理已分配的内存
            for (int j = 0; j < i; j++) {
                if(ptrs[j]) free(ptrs[j]);
            }
            exit(EXIT_FAILURE);
        }
        printf("  已分配块 %d (索引 %d) @ %p\n", i + 1, i, ptrs[i]);
        // 可选：访问内存以确保物理页面被映射 (如果需要观察 RSS 变化)
        // memset(ptrs[i], 0, 1); // 写入第一个字节
    }
    check_memory_status("分配完 6 * 128MB 之后");

    // 2. 释放第 2、3、5 号内存块 (对应索引 1, 2, 4)
    printf("\n[操作 2] 正在释放第 2, 3, 5 号 (索引 1, 2, 4) 内存块...\n");
    if (ptrs[1]) { free(ptrs[1]); printf("  已释放块 2 (索引 1) @ %p\n", ptrs[1]); ptrs[1] = NULL; }
    if (ptrs[2]) { free(ptrs[2]); printf("  已释放块 3 (索引 2) @ %p\n", ptrs[2]); ptrs[2] = NULL; }
    if (ptrs[4]) { free(ptrs[4]); printf("  已释放块 5 (索引 4) @ %p\n", ptrs[4]); ptrs[4] = NULL; }
    check_memory_status("释放完第 2, 3, 5 号块之后");

    // 3. 再分配一个 1024MB (1GB) 的内存块
    printf("\n[操作 3] 正在分配 1024MB 内存块...\n");
    large_ptr = malloc(MALLOC_SIZE_1024M);
    if (large_ptr == NULL) {
        perror("分配 1024MB 内存失败");
        // 清理
        for(i = 0; i < NUM_ALLOCS; i++) { if(ptrs[i]) free(ptrs[i]); }
        exit(EXIT_FAILURE);
    }
    printf("  已分配 1024MB @ %p\n", large_ptr);
    // 可选：访问内存
    // memset(large_ptr, 0, 1);
    check_memory_status("分配完 1024MB 之后");

    // 4. 预测并分配 64MB
    printf("\n[操作 4] 准备分配 64MB 内存块...\n");
    printf(">>> 请预测：这块 64MB 内存会分配在哪个地址范围？<<<\n");
    printf("    a) 重用之前释放的 128MB 块之一的空间？(哪个？)\n");
    printf("    b) 在现有堆顶或其他区域扩展？\n");
    printf("    c) 创建一个新的独立内存映射区域？\n");

    final_ptr = malloc(MALLOC_SIZE_64M);
    if (final_ptr == NULL) {
        perror("分配 64MB 内存失败");
        // 清理
        if(large_ptr) free(large_ptr);
        for(i = 0; i < NUM_ALLOCS; i++) { if(ptrs[i]) free(ptrs[i]); }
        exit(EXIT_FAILURE);
    }
    printf("  已分配 64MB @ %p\n", final_ptr);
    // 可选：访问内存
    // memset(final_ptr, 0, 1);
    check_memory_status("分配完 64MB 之后");

    // 5. 清理所有剩余内存
    printf("\n[操作 5] 正在清理所有剩余内存...\n");
    if (large_ptr) { free(large_ptr); printf("  已释放 1024MB @ %p\n", large_ptr); large_ptr = NULL; }
    if (final_ptr) { free(final_ptr); printf("  已释放 64MB @ %p\n", final_ptr); final_ptr = NULL; }
    for (i = 0; i < NUM_ALLOCS; i++) {
        if (ptrs[i] != NULL) {
            free(ptrs[i]);
            printf("  已释放块 %d (索引 %d) @ %p\n", i + 1, i, ptrs[i]);
            ptrs[i] = NULL;
        }
    }
    check_memory_status("最终清理之后");

    printf("\n实验程序结束。\n");
    return 0;
}
